﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace Sped.Sped
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ProgId("SpedPisCofins")]
    [ComVisible(true)]
    public class SpedPisCofins
    {
        #region Bloco 0
        private List<Reg0000> Registro0000 = new List<Reg0000>();
        private List<Reg0001> Registro0001 = new List<Reg0001>();
        private List<Reg0100> Registro0100 = new List<Reg0100>();
        private List<Reg0110> Registro0110 = new List<Reg0110>();
        private List<Reg0111> Registro0111 = new List<Reg0111>();
        private List<Reg0140> Registro0140 = new List<Reg0140>();
        private List<Reg0150> Registro0150 = new List<Reg0150>();
        private List<Reg0190> Registro0190 = new List<Reg0190>();
        private List<Reg0200> Registro0200 = new List<Reg0200>();
        private List<Reg0400> Registro0400 = new List<Reg0400>();
        private List<Reg0450> Registro0450 = new List<Reg0450>();
        private List<Reg0500> Registro0500 = new List<Reg0500>();
        private List<Reg0600> Registro0600 = new List<Reg0600>();
        #endregion

        #region Bloco A
        private List<RegA001> RegistroA001 = new List<RegA001>();
        #endregion

        #region Configurações
        //public string StringDeConexao { private get; set; }
        private int LinhaAtual = 0;
        #endregion

        #region Acoes
        public void AdicionaReg(IBloco Reg)
        {
            #region Bloco 0
            if (Reg is Reg0000)
                this.Registro0000.Add((Reg0000)Reg);
            if (Reg is Reg0001)
                this.Registro0001.Add((Reg0001)Reg);
            if (Reg is Reg0100)
                this.Registro0100.Add((Reg0100)Reg);
            if (Reg is Reg0110)
                this.Registro0110.Add((Reg0110)Reg);
            if (Reg is Reg0111)
                this.Registro0111.Add((Reg0111)Reg);
            if (Reg is Reg0140)
                this.Registro0140.Add((Reg0140)Reg);
            if (Reg is Reg0150)
                this.Registro0150.Add((Reg0150)Reg);
            if (Reg is Reg0190)
                this.Registro0190.Add((Reg0190)Reg);
            if (Reg is Reg0200)
                this.Registro0200.Add((Reg0200)Reg);
            if (Reg is Reg0400)
                this.Registro0400.Add((Reg0400)Reg);
            if (Reg is Reg0450)
                this.Registro0450.Add((Reg0450)Reg);
            if (Reg is Reg0500)
                this.Registro0500.Add((Reg0500)Reg);
            if (Reg is Reg0600)
                this.Registro0600.Add((Reg0600)Reg);
            #endregion

            #region Bloco A
            if (Reg is RegA001)
                this.RegistroA001.Add((RegA001)Reg);
            #endregion
        }

        private void LeRegistro(IBloco Reg, ref StringBuilder Sped, ref StringBuilder Erros)
        {
            LinhaAtual++;
            var Erro = string.Empty;
            if (!Reg.ValidaRegistro(ref Erro))
            {
                Erros.AppendLine(String.Format("Linha {0}", LinhaAtual));
                Erros.AppendLine(Erro);
            }
            Sped.AppendLine(Reg.Layout());
            return ;
        }

        public bool GeraArquivo(string Destino)
        {
            StringBuilder Sped = new StringBuilder("");
            StringBuilder Erros = new StringBuilder("");
            
            this.LinhaAtual = 0;

            #region Bloco 0
            foreach (Reg0000 Reg in Registro0000)
            {
                this.LeRegistro(Reg, ref Sped, ref Erros);
            }
            var oReg0001 = new Reg0001();
            this.LeRegistro(oReg0001, ref Sped, ref Erros);
            foreach (Reg0100 Reg in Registro0100)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0110 Reg in Registro0110)
                this.LeRegistro(Reg, ref Sped, ref Erros);
            
            foreach (Reg0111 Reg in Registro0111)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0140 Reg in Registro0140)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0150 Reg in Registro0150)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0190 Reg in Registro0190)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0200 Reg in Registro0200)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0400 Reg in Registro0400)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0450 Reg in Registro0450)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0500 Reg in Registro0500)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            foreach (Reg0600 Reg in Registro0600)
                this.LeRegistro(Reg, ref Sped, ref Erros);

            var oReg0990 = new Reg0990();
            oReg0990.QTD_LIN_0 = (Registro0000.Count + Registro0001.Count + Registro0100.Count + Registro0110.Count + Registro0111.Count +
                    Registro0140.Count + Registro0150.Count + Registro0190.Count + Registro0200.Count + Registro0400.Count + 
                    Registro0450.Count + Registro0500.Count + Registro0600.Count + 1);
            this.LeRegistro(oReg0990, ref Sped, ref Erros);
            #endregion

            #region Bloco A
            var RegistrosA = 0;

            foreach (RegA001 Reg in RegistroA001)
            {
                this.LeRegistro(Reg, ref Sped, ref Erros);
                RegistrosA++;
                foreach (RegA010 Reg010 in Reg.RegistroA010)
                {
                    this.LeRegistro(Reg010, ref Sped, ref Erros);
                    RegistrosA++;
                    foreach (RegA100 Reg100 in Reg010.RegistroA100)
                    {
                        this.LeRegistro(Reg, ref Sped, ref Erros);
                        RegistrosA++;
                        foreach (RegA120 Reg120 in Reg100.RegistroA120)
                        {
                            this.LeRegistro(Reg120, ref Sped, ref Erros);
                            RegistrosA++;
                        }
                        foreach (RegA170 Reg170 in Reg100.RegistroA170)
                        {
                            this.LeRegistro(Reg170, ref Sped, ref Erros);
                            RegistrosA++;
                        }
                    }
                }
            }

            var Reg990 = new RegA990();
            Reg990.QTD_LIN_A = ++RegistrosA;
            this.LeRegistro(Reg990, ref Sped, ref Erros);
            #endregion

            System.IO.File.WriteAllText(Destino, Sped.ToString(), Encoding.GetEncoding("ISO-8859-1"));

            //TextWriter tw = new StreamWriter(Destino);
            //tw.Write(Sped.ToString());
            //tw.Close();

            if (Erros.Length > 0)
            {
                System.IO.File.WriteAllText(Destino.Trim() + ".log", Erros.ToString(), Encoding.GetEncoding("ISO-8859-1"));
                //TextWriter twErros = new StreamWriter(Destino.Trim() + ".log");
                //twErros.Write(Erros.ToString());
                //twErros.Close();
            }
            
            if (File.Exists(Destino))
                Process.Start(Destino);

            if (File.Exists(Destino.Trim() + ".log"))
                Process.Start(Destino.Trim() + ".log");
            return true;
        }
        #endregion
    }
}
